# vBulletin visitor messages
# by Cee Pee

import forumapi
import re
from deps.Form import Form

__all__ = [
	# Utilities
	"post_visitor_message",
	
	# Extensible objects
	"VisitorMessage",
]

## Utilities ##

def get_vm_list(result, data, page_soup, first_page=False, session=None, user=None, vm=None, **kw):
	"""Given a `BeautifulSoup` of a page and a list, adds `VisitorMessage`
	objects to that list representing the messages on the page."""
	
	if first_page and vm and vm in result.items:
		return(False)
	
	vm_soup = page_soup.find(id="visitor_messaging")
	
	if not vm_soup:
		return(False)
	
	pager = vm_soup.find("div", "pagenav")
	result.get_pager(pager)
	
	list_soup = vm_soup.find(id="message_list")
	
	continue_pages = True
	
	for item in list_soup.findAll("li", recursive=False):
		if item.find("div", "smallfont deletedmessage"):
			# Ignore deleted messages
			continue
		
		vm_id = int(re.match("vmessage(\d+)", item["id"]).group(1))
		
		user_link = item.find("a", "smallfont username")
		
		user_id = int(forumapi.qs_dict_from_url(user_link["href"])["u"][0])
		
		source_user = forumapi.User(session, id=user_id)
		source_user.retrieve_name(user_link)
		
		time = session.get_datetime(item.find("div", "visitor_message_date"))
		
		body = item.find("div", "visitor_message_body")
		content = session.module.get_attr("BBCode")(session, body)
		
		visitor_message = VisitorMessage(session, id=vm_id, source_user=source_user, target_user=user, content=content, time=time)
		
		if vm == visitor_message:
			continue_pages = False
		
		data.append(visitor_message)
	
	return(continue_pages)

def post_visitor_message(user, message):
	"""Posts a visitor message to a user.
	
	Returns a `VisitorMessage` object of the newly created message on
	success."""
	
	if not isinstance(user, forumapi.User):
		raise(ValueError("User must be a user object."))
	
	page = user.session.get_page("visitormessage.php?do=message&u={0}".format(user.id))
	
	page_soup = user.session.soup(page)
	
	form_soup = page_soup.find("form", action=lambda url: "visitormessage.php" in url)
	
	if not form_soup:
		raise(forumapi.PermissionError(user.session.get_error(page_soup) or "Cannot post visitor message to user."))
	
	form_data = Form(form_soup, session=user.session)
	
	form_data["message"] = message
	
	result = form_data.submit()
	
	result_soup = user.session.soup(result)
	
	result_form = result_soup.find("form", action=lambda url: "member.php" in url)
	if not result_form:
		raise(forumapi.PermissionError(user.session.get_error(result_soup) or "Failed to post visitor message."))
	
	result_qs = forumapi.qs_dict_from_url(dict(result_form.attrs)["action"])
	id = int(result_qs["vmid"][0])
	
	return(VisitorMessage(user.session, id=id, source_user=user.session.user, target_user=user, content=message))

## Hooks ##

def _user_profile_query(user=None, kw=None, query=None, **kwargs):
	if "vm" in kw:
		kw["vm"] = VisitorMessage.obj(user.session, kw["vm"])
		query["vmid"] = kw["vm"].id

def _user_profile(user=None, kw=None, query=None, page=None, profile_soup=None, **kwargs):
	vm_tab = profile_soup.find(id="visitor_messaging")
	if vm_tab:
		if "vm" in kw:
			vm = kw["vm"]
		else:
			vm = None
		
		if "vm_pages" in kw:
			vm_pages = int(kw["vm_pages"])
		else:
			vm_pages = 1
		
		if user._visitor_messages:
			user._visitor_messages.get_pages(get_vm_list, response=page, pages=vm_pages, user=user, vm=vm)
		else:
			vm_query = query.copy()
			vm_query["tab"] = "visitor_messaging"
			
			user._visitor_messages = user.session.get_pages(get_vm_list, response=page, post_data=vm_query, method="get", pages=vm_pages, user=user, vm=vm)
	else:
		user._visitor_messages = False

forumapi.hooks.add("vb_user_profile_query", _user_profile_query)
forumapi.hooks.add("vb_user_profile", _user_profile)

## Classes ##

class VisitorMessage(forumapi.ExtensibleObject):
	"""A visitor message. It knows its ID, and might know the user it was posted
	by and for."""
	
	@classmethod
	def obj(self, session, *a, **kw):
		if isinstance(a[0], cls):
			return(a[0])
		elif isinstance(a[0], int):
			return(cls(session, *a[1:], id=a[0], **kw))
		else:
			return(None)
	
	def __init__(self, session, id=None, source_user=None, target_user=None, content=None, time=None):
		if not id:
			raise(ValueError("ID required."))
		
		self.session = session
		
		self._id = id
		
		self._source_user = self.module.get_attr("User").obj(session, source_user)
		self._target_user = self.module.get_attr("User").obj(session, target_user)
		
		self._content = content
		
		self._time = time
		
		self._find_instances()
	
	def _merge(self, other):
		if self._source_user:
			other._source_user = self._source_user
		if self._target_user:
			other._target_user = self._target_user
		
		self._merge_obj(other, "_content")
		
		if self._time:
			other._time = self._time
	
	@property
	def data(self):
		return({
			"id": self._id,
			"source_user": int(self.source_user) if self._source_user else None,
			"target_user": int(self.target_user) if self._target_user else None,
			"content": forumapi._flatten_data(self._content),
			"time": self._time
		})
	
	@property
	def id(self):
		if self._id:
			return(self._id)
		else:
			raise(NotImplementedException("Unable to retrieve VM ID."))
	
	@property
	def source_user(self):
		if self._source_user:
			return(self._source_user)
		elif self._target_user:
			self.target_user.get_profile(vm=self)
			return(self._source_user)
		else:
			raise(NotImplementedException("Cannot retrieve VM source user."))
	
	@property
	def target_user(self):
		if self._target_user:
			return(self._target_user)
		else:
			raise(NotImplementedException("Cannot retrieve VM target user."))
	
	@property
	def content(self):
		if self._content:
			return(self._content)
		else:
			self.target_user.get_profile(vm=self)
			return(self._content)
	
	@property
	def time(self):
		if self._time:
			return(self._time)
		else:
			self.target_user.get_profile(vm=self)
			return(self._time)
	
	def __eq__(self, other):
		if isinstance(other, VisitorMessage):
			return(self.id == other.id)
		elif isinstance(other, int):
			return(self.id == other)
		else:
			return(False)
	
	def __int__(self):
		return(self.id)
	
	def __repr__(self):
		return("<VisitorMessage {self.id}{0}{1}\">".format(" by {self._source_user}".format(self=self) if self._source_user else "", " to {self._target_user}".format(self=self) if self._target_user else "", self=self))
